package com.pdool.game.core.server;

import cn.hutool.core.net.url.UrlQuery;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.pdool.common.constants.Constant;
import com.pdool.game.constant.SessionAttr;
import com.pdool.game.core.config.GameConfig;
import com.pdool.game.core.msg.MsgTask;
import com.pdool.game.core.msg.UserMsgQueue;
import com.pdool.game.logic.enums.LogPointType;
import com.pdool.game.logic.event.LoginEvent;
import com.pdool.game.logic.mgr.UserMgr;
import com.pdool.game.logic.service.LoginService;
import com.pdool.game.logic.util.LogUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.BinaryMessage;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.BinaryWebSocketHandler;

import javax.annotation.Resource;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Map;

/**
 * 服务器
 */
@Component
@Slf4j
public class GameWebsocketServer extends BinaryWebSocketHandler {
    @Autowired
    ThreadPoolTaskExecutor logicThreadPool;
    @Resource
    private GameConfig gameConfig;

    @Resource
    LoginService loginService;

    @Autowired
    private ApplicationEventPublisher publisher;

    @Resource
    RedisTemplate redisTemplate;

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws IOException {
        URI uri = session.getUri();
        if (uri == null) {
            session.close();
            return;
        }
        UrlQuery of = UrlQuery.of(uri.toString(), Charset.defaultCharset());
        Map<CharSequence, CharSequence> queryMap = of.getQueryMap();
        String token = (String) queryMap.get("token");
        JWT jwt = JWTUtil.parseToken(token);
        Object roleIdObj = jwt.getPayload("roleId");
        long roleId = Long.parseLong(roleIdObj.toString());

        if (UserMgr.getInstance().getSessionMap().containsKey(roleId)) {
            session.sendMessage(new TextMessage("已经登录"));
            session.close();
            return;
        }
        session.getAttributes().put(SessionAttr.ROLE_ID, roleId);
        session.getAttributes().put(SessionAttr.LOGIN_TIME, System.currentTimeMillis());

        UserMgr.getInstance().getSessionMap().put(roleId, session);

        //  todo 登录操作
        publisher.publishEvent(new LoginEvent(this, roleId));
        log.error("当前在线人数：" + UserMgr.getInstance().getSessionMap().size());

        redisTemplate.opsForHash().increment(Constant.GAME_ONLINE_COUNT,gameConfig.getServerId(),1);

        LogUtil.getInstance().recordLog(roleId, LogPointType.LOGIN_COUNT, 1);

    }

    @Override
    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {
        Map<String, Object> attributes = session.getAttributes();
        Long roleId = (Long) session.getAttributes().get(SessionAttr.ROLE_ID);
        UserMsgQueue queue = (UserMsgQueue) attributes.computeIfAbsent(SessionAttr.MSG_QUEUE, (key) -> new UserMsgQueue(session, logicThreadPool));
        MsgTask msgTask = new MsgTask(session, message, roleId);
        queue.addQueue(msgTask);

    }


    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        log.error("连接出错  【{}】", session.getId());
        loginService.logOut(session);
//        log.error("", exception);
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        log.error("关闭连接  sessionId :{} closeStatus {}", session.getId(), closeStatus.getReason());
        loginService.logOut(session);

    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    public static void main(String[] args) {
        String pong = "pong";
        System.out.println(pong.getBytes().toString());
    }
}